package lu.uni.adtool.ui;

import java.awt.Frame;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;

import lu.uni.adtool.Options;

/**
 * Provides static methods for choosing file to open or save.
 * 
 * @author Piot Kordy
 */
public class FileHandler
{
  protected JLabel statusLine;
  protected String treeFileName;
  protected String layoutFileName;
  protected Frame mainWindow;
  protected JFileChooser fc;
  protected JCheckBox saveLayout;
  private String tempFileName;
  /**
   * Constructs a new instance.
   */
  public FileHandler(Frame window)
  {
    this(null,window);
  }

  /**
   * Constructs a new instance.
   * @param status status line to which we report.
   */
  public FileHandler(final JLabel status,final Frame window)
  {
    treeFileName = "adtree.adt";
    layoutFileName = "adtree.adl";
    tempFileName = "";
    tempFileName = "";
    statusLine = status;
    mainWindow = window;
    initFileChooser();
  }
  /**
   * Shows save dialog.
   * 
   * @return stream to wchich we can write or null.
   */
  public ObjectOutputStream getSaveTreeStream()
  {
    fc.setAcceptAllFileFilterUsed(true);
    FileFilter filter = new FileNameExtensionFilter("ADTree file", "adt", "ADT", "Adt");
    saveLayout.setVisible(true);
    fc.setSelectedFile(new File(treeFileName));
    fc.setDialogTitle("Save Attack Defence Tree...");
    ObjectOutputStream result = getSaveStream(filter);
    if (result != null){
      treeFileName = tempFileName;
    }
    return result;
  }
  /**
   * Shows export dialog.
   * 
   * @return stream to which we can write or null.
   */
  public FileOutputStream getExportTreeStream(String extension)
  {
    FileFilter filter = null;
    if (extension.equals("pdf")){
      filter = new FileNameExtensionFilter("Pdf file", "pdf", "PDF", "Pdf");
    }
    else if (extension.equals("png")){
      filter = new FileNameExtensionFilter("PNG image", "png", "PNG", "Png");
    }
    else if (extension.equals("jpg")){
      filter = new FileNameExtensionFilter("JPEG image", "jpg", "JPG", "Jpg","jpeg", "JPEG", "Jpeg");
    }
    else if (extension.equals("tex")){
      filter = new FileNameExtensionFilter("LaTeX file", "tex", "TEX", "Tex", "latex", "LATEX", "LaTeX", "Latex");
    }
    saveLayout.setVisible(false);
    fc.setDialogTitle("Export tree...");
    FileOutputStream out = null;
    fc.setSelectedFile(new File("adtree."+extension));
    fc.resetChoosableFileFilters();
    fc.setAcceptAllFileFilterUsed(false);
    fc.setFileFilter(filter);
    int returnVal = fc.showSaveDialog(this.mainWindow);
    if (returnVal == JFileChooser.APPROVE_OPTION) {
      File file = fc.getSelectedFile();
      report("Exporting to: " + file.getName() + ".");
      try {
        out =new FileOutputStream(file);
        tempFileName = file.getName();
      }
      catch (FileNotFoundException e) {
        report("File not found:\""+file.getName()+"\".");
      }
      catch (IOException e) {
        report("There was IO problem opening a file:\""+file.getName()+"\".");
      }
    }
    else {
      report("Save command cancelled by the user.");
    }
    return out;
  }
  /**
   * Shows save dialog.
   * 
   * @return stream to which we can write or null.
   */
  public ObjectOutputStream getSaveLayoutStream()
  {
    fc.setAcceptAllFileFilterUsed(true);
    FileFilter filter = new FileNameExtensionFilter("Layout file", "adl", "ADL", "Adl");
    saveLayout.setVisible(false);
    fc.setSelectedFile(new File(layoutFileName));
    fc.setDialogTitle("Save Layout...");
    return getSaveStream(filter);
  }
  /**
   * Shows save dialog.
   * 
   * @return stream to wchich we can write or null.
   */
  public ObjectOutputStream getSaveStream(FileFilter filter)
  {
    ObjectOutputStream out = null;
    fc.resetChoosableFileFilters();
    fc.setFileFilter(filter);
    int returnVal = fc.showSaveDialog(this.mainWindow);
    if (returnVal == JFileChooser.APPROVE_OPTION) {
      File file = fc.getSelectedFile();
      // This is where a real application would open the file.
      report("Saving to: " + file.getName() + ".");
      try {
        out = new ObjectOutputStream(new FileOutputStream(file));
        tempFileName = file.getName();
      }
      catch (FileNotFoundException e) {
        report("File not found:\""+file.getName()+"\".");
      }
      catch (IOException e) {
        report("There was IO problem opening a file:\""+file.getName()+"\".");
      }
    }
    else {
      report("Save command cancelled by the user.");
    }
    return out;
  }
  /**
   * Shows open file dialog.
   * 
   * @return Stream from which we can read or null if no file was open.
   */
  public ObjectInputStream getLoadTreeStream()
  { 
    FileFilter filter = new FileNameExtensionFilter("Tree file", "adt", "ADT", "Adt");
    saveLayout.setVisible(false);
    fc.setSelectedFile(new File(treeFileName));
    fc.setDialogTitle("Load Atack Defence Tree...");
    ObjectInputStream result = getLoadStream(filter);
    if (result != null){
      treeFileName = tempFileName;
    }
    return result;
  }
  /**
   * Shows open file dialog.
   * 
   * @return Stream from which we can read or null if no file was open.
   */
  public ObjectInputStream getLoadLayoutStream()
  { 
    FileFilter filter = new FileNameExtensionFilter("Layout file", "adl", "ADL", "Adl");
    fc.setDialogTitle("Load Layout...");
    fc.setSelectedFile(new File(layoutFileName));
    saveLayout.setVisible(false);
    return getLoadStream(filter);
  }
  /**
   * Shows open file dialog.
   * 
   * @return Stream from which we can read or null if no file was open.
   */
  private ObjectInputStream getLoadStream(FileFilter filter)
  {
    ObjectInputStream in = null;
    fc.resetChoosableFileFilters();
    fc.setFileFilter(filter);
    int returnVal = fc.showOpenDialog(this.mainWindow);

    if (returnVal == JFileChooser.APPROVE_OPTION) {
      File file = fc.getSelectedFile();
      tempFileName = file.getName();
      // This is where a real application would open the file.
      report("Opening: " + file.getName() + ".");
      try {
        in = new ObjectInputStream(new FileInputStream(file));
      }
      catch (FileNotFoundException e) {
        report("File not found.");
      }
      catch (IOException e) {
        report("There was IO problem opening a file:\""+file.getName()+"\"");
      }
    }
    else {
      report("Open command cancelled by the user.");
    }
    return in;
  }
  /**
   * Initializes fileChooser
   * 
   * @return new checkbox
   */
  private void initFileChooser()
  {
    JPanel jp = new JPanel();
    fc = new JFileChooser()
    {
      @Override
      public void approveSelection()
      {
        File f = getSelectedFile();
        if (f.exists() && getDialogType() == SAVE_DIALOG) {
          int result = JOptionPane.showConfirmDialog(this,
              "The file exists, overwrite?", "Existing file",
              JOptionPane.YES_NO_CANCEL_OPTION);
          switch (result) {
            case JOptionPane.YES_OPTION:
              super.approveSelection();
              return;
            case JOptionPane.NO_OPTION:
              return;
            case JOptionPane.CLOSED_OPTION:
              return;
            case JOptionPane.CANCEL_OPTION:
              cancelSelection();
              return;
          }
        }
        super.approveSelection();
      };
    };

    fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
// Add "show hidden files" CheckBoxMenuItem
    JCheckBox showHiddenCheckBox = new JCheckBox();
    saveLayout = new JCheckBox();
    saveLayout.setText("Include Layout");
    saveLayout.setSelected(Options.main_saveLayout);
    saveLayout.addActionListener(new ActionListener()
    {
      @Override
      public void actionPerformed(ActionEvent e)
      {
        JCheckBox source = (JCheckBox) e.getSource();
        Options.main_saveLayout = source.isSelected();
      }
    });

    showHiddenCheckBox.setText("Show hidden");
    showHiddenCheckBox.setMnemonic(KeyEvent.VK_H);
    showHiddenCheckBox.setSelected(!fc.isFileHidingEnabled());
    showHiddenCheckBox.addActionListener(new ActionListener()
    {
      @Override
      public void actionPerformed(ActionEvent e)
      {
        JCheckBox source = (JCheckBox) e.getSource();
        boolean showHidden = source.isSelected();
        //System.out.println("hid="+showHidden);
        //fc.firePropertyChange(JFileChooser.FILE_HIDING_CHANGED_PROPERTY, showHidden, !showHidden);
        fc.setFileHidingEnabled(!showHidden);
      }
    });
    //fc.setFileHidingEnabled(false);
    jp.setLayout(new BoxLayout(jp, BoxLayout.PAGE_AXIS));
    saveLayout.setVisible(true);
    jp.add(saveLayout);
    jp.add(showHiddenCheckBox);
    fc.setAccessory(jp);
  }
  /**
   * Update status line with text.
   * 
   * @param s new text for status line
   */
  private void report(final String s)
  {
    if (statusLine == null) {
      System.out.println(s);
    }
    else {
      statusLine.setText(s);
    }
  }

  /**
   * Gets the treeFileName for this instance.
   *
   * @return The treeFileName.
   */
  public String getTreeFileName()
  {
    return this.treeFileName;
  }

}
